/**
 * @file   opencv_ctrl.h
 * @brief  opencv
 * @encode UTF-8
 * @log    date        author      notes
 *         2021.09.07  Jimmy       first version
 */
#ifndef __OPENCV_CTRL_H_ 
#define __OPENCV_CTRL_H_ 

#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/opencv_modules.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc_c.h"      //包含IplImage
#include <opencv2/highgui/highgui_c.h>

#include <mutex>
#include <functional>
#include <cstring>

#include "../inner_libs/usr/include/utils/maps.h"

namespace sim_shell
{
	enum sim_event_t
	{
		SME_NULL = 0,
		SME_PATHING,
	};
}

typedef std::function<void (sim_shell::sim_event_t event)> eventCbType;

class Simu
{
private:
	static Simu * mInstance;

	static inline Simu * Instance()
	{
		return mInstance;
	}

	static void mouseCallback(int event, int x, int y, int flags, void * userdata);
	
public:
	Simu();
	Simu(std::string path, std::string winName);
	~Simu();

	void registEventCallback(eventCbType callback)
	{
		mEventCallback = callback;
	}

	/* 获取地图 */
	void getMap(MapData & mapData);
	/* 发布路径到窗口显示 */
	void  pubPath(std::vector<Point> path);
	/* 获取世界坐标下的起点 */
	Point getStartPoint(void);
	/* 获取世界坐标下的终点 */
	Point getEndPoint(void);
	/* 事件监听 */
	bool eventListen(void);
	/* 获取事件 */
	sim_shell::sim_event_t inline getSimEvent(void)
	{	
		return mSimEvent;
	}

	inline float getMatScaler(void)
	{
		return mScaler;
	}

	inline uint8_t getMapPixel(int index)
	{
		return mMapData.map.at(index);
	}

private:
	int      mShowWidth;
	int      mShowHeight;

	int      mGrayWidth;
	int      mGrayHeight;

	cv::Mat  mMatSrc;		/* 彩色图，用于保存原始的图像 */
	cv::Mat  mMatShow;		/* 彩色图，用于显示 */
	cv::Mat  mMatGray;		/* 灰度图，用于地图计算 */

	float    mScaler;		/* 图像放大缩小倍数 */

	bool     mIsStartSet;
	bool     mIsEndSet;
	bool     mIsPathSet;

	Point    mStartPos;
	Point    mEndPos;

	std::vector<Point> mPath;
	std::vector<Point> mShowPath;

	bool mSimEventTigger = false;
	sim_shell::sim_event_t mSimEvent;

	std::string mImgPath;
	std::string mWinName;

	eventCbType mEventCallback = nullptr;

	bool mShowThreadRun;
	bool mListenThreadRun;

	MapData mMapData;

private:
	bool loadImage(void);

	void showThread(void);
	void listenKeyThread(void);

	void display(void);
	void listenKey(uint16_t sleep);

	void drawGrid(cv::Mat & mat);
	void drawStartPoint(Point p);
	void drawEndPoint(Point p);
	void drawPath();

	void setStartPoint(Point startP);
	void setEndPoint(Point endP);

	void testImage(void);

private:
	float mCarLineVel;
	float mCarAngVel;
	
	Point mCarPos;
	float mCarPhi;

	void drawCarrier(void);

};


#endif	/* __OPENCV_CTRL_H_ */
